<template>
  <div className="editor">
    <el-alert
      v-show="uploading1"
      style="margin-bottom: 10px;"
      type="warning"
      effect="dark">
      <div>上传中<i class="el-icon-loading"></i></div>
    </el-alert>
    <div :id="id">
    </div>
  </div>
</template>

<script>
import { fileServer } from '@/filters'
import E from "wangeditor"
// 获取必要的变量，这些在下文中都会用到
const { $, BtnMenu, DropListMenu, PanelMenu, DropList, Panel, Tooltip } = E
// 第一，菜单 class ，Button 菜单继承 BtnMenu class
/**
* 转义HTML标签的方法
* @param  {String} str 需要转义的HTML字符串
* @return {String}     转义后的字符串
*/
var funEncodeHTML = function (str) {
  if (typeof str == 'string') {
    return str.replace(/<|&|>/g, function (matches) {
      return ({
        '<': '&lt;',
        '>': '&gt;',
        '&': '&amp;'
      })[matches];
    });
  }

  return '';
}

/**
 * 反转义HTML标签的方法
 * @param  {String} str 需要反转义的字符串
 * @return {String}     反转义后的字符串
 */
var funDecodeHTML = function (str) {
  if (typeof str == 'string') {
    return str.replace(/&lt;|&gt;|&amp;/g, function (matches) {
      return ({
        '&lt;': '<',
        '&gt;': '>',
        '&amp;': '&'
      })[matches];
    });
  }

  return '';
};

class GetSource extends BtnMenu {
  constructor(editor) {
    // data-title属性表示当鼠标悬停在该按钮上时提示该按钮的功能简述
    const $elem = E.$(
      `<div class="w-e-menu" data-title="源码">
      <div class="w-e-up-btn">
        <i class="w-e-icon-terminal"></i>
      </div>
    </div>`,
    );
    super($elem, editor);
  }
  showSource() {
    this.isHTML = !this.isHTML
    let source = this.editor.txt.html()
    if (this.isHTML) {
      source = funEncodeHTML(source)
    } else {
      source = funDecodeHTML(this.editor.txt.text())
    }
    this.editor.txt.html(source)
  }
  clickHandler() {
    this.showSource()
    this.tryChangeActive()
  }
  tryChangeActive() {
    if (this.isHTML) {
      this.active()
    } else {
      this.unActive()
    }
  }
}

export default {
  name: 'editor',
  data() {
    return {
      uploading1: false,
      content: "",
      editor: null,
      info_: null
    }
  },
  model: {
    prop: 'desc',
    event: 'change'
  },
  watch: {
    isClear(val) {
      // console.log(val)
      if (val) {
        this.editor.txt.clear()
        // this.info_=null
      }
    },
    desc(value) {
      // console.log("desc",value)
      if (value != this.editor.txt.html()) {
        this.editor.txt.html(this.desc)
      }
    }
  },
  props: {
    id: {
      type: String,
      default: "e"
    },
    desc: {
      type: String,
      default: ""
    },
    //业务中我们经常会有添加操作和编辑操作，添加操作时，我们需清除上一操作留下的缓存
    isClear: {
      type: Boolean,
      default: false
    }
  },

  methods: {
    initE() {
      const that = this
      this.editor = new E('#' + this.id)
      // console.log(this.editor)
      this.editor.config.pasteFilterStyle = false
      this.editor.config.onchangeTimeout = 1000 // 单位 ms
      // 配置粘贴文本的内容处理
      this.editor.config.pasteTextHandle = function(pasteStr) {
        pasteStr = pasteStr.replace(/<img src="https:\/\/mmbiz.qpic.cn/g, '<img referrerpolicy="no-referrer" src="https://mmbiz.qpic.cn')
        // 对粘贴的文本进行处理，然后返回处理后的结果
        return pasteStr
      }
      this.editor.config.uploadFileName = 'file'
      this.editor.config.uploadImgServer = `/prod-api/ajax/upload` // 你的服务器地址
      this.editor.config.uploadImgHooks = {
        before: (xhr, editor, files) => {
          // 图片上传之前触发
          // xhr 是 XMLHttpRequst 对象，editor 是编辑器对象，files 是选择的图片文件

          // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
          // return {
          //     prevent: true,
          //     msg: '放弃上传'
          // }
          this.$message.warning('上传中，请耐心等候')
          this.uploading1 = true
          this.$forceUpdate()
        },
        success: (xhr, editor, result) => {
          // 图片上传并返回结果，图片插入成功之后触发
          // xhr 是 XMLHttpRequst 对象，editor 是编辑器对象，result 是服务器端返回的结果
          // this.uploading1 = false
        },
        fail: (xhr, editor, result) => {
          // 图片上传并返回结果，但图片插入错误时触发
          // xhr 是 XMLHttpRequst 对象，editor 是编辑器对象，result 是服务器端返回的结果
        },
        error: (xhr, editor) => {
          // 图片上传出错时触发
          // xhr 是 XMLHttpRequst 对象，editor 是编辑器对象
          this.uploading1 = false
        },
        timeout: function (xhr, editor) {
          // 图片上传超时时触发
          // xhr 是 XMLHttpRequst 对象，editor 是编辑器对象
        },

        // 如果服务器端返回的不是 {errno:0, data: [...]} 这种格式，可使用该配置
        // （但是，服务器端返回的必须是一个 JSON 格式字符串！！！否则会报错）
        customInsert: (insertImg, result, editor) => {
          // 图片上传并返回结果，自定义插入图片的事件（而不是编辑器自动插入图片！！！）
          // insertImg 是插入图片的函数，editor 是编辑器对象，result 是服务器端返回的结果

          // 举例：假如上传图片成功后，服务器端返回的是 {url:'....'} 这种格式，即可这样插入图片：
          console.log(result.data.url)
          var url = result.data.url
          insertImg(fileServer(url))
          this.uploading1 = false
          // result 必须是一个 JSON 格式字符串！！！否则报错
        }
      }
      this.editor.config.uploadVideoName = 'file'
      this.editor.config.uploadVideoServer = `/prod-api/ajax/upload` // 你的服务器地址
      this.editor.config.uploadVideoHooks = {
        // 上传视频之前
        before: (xhr) => {
          console.log(xhr)
          this.$message.warning('上传中，请耐心等候')
          this.uploading1 = true
          this.$forceUpdate()
        },
        // 视频上传并返回了结果，视频插入已成功
        success: function(xhr) {
          console.log('success', xhr)
          // this.uploading1 = false
        },
        // 视频上传并返回了结果，但视频插入时出错了
        fail: function(xhr, editor, resData) {
          console.log('fail', resData)
        },
        // 上传视频出错，一般为 http 请求的错误
        error: (xhr, editor, resData) => {
          console.log('error', xhr, resData)
          this.uploading1 = false
        },
        // 上传视频超时
        timeout: function(xhr) {
          console.log('timeout')
        },
        // 视频上传并返回了结果，想要自己把视频插入到编辑器中
        // 例如服务器端返回的不是 { errno: 0, data: { url : '.....'} } 这种格式，可使用 customInsert
        customInsert: (insertVideoFn, result) => {
          // result 即服务端返回的接口
          console.log('customInsert', result)

          // insertVideoFn 可把视频插入到编辑器，传入视频 src ，执行函数即可
          insertVideoFn(fileServer(result.data.url))
          this.uploading1 = false
        }
      }
      this.editor.config.onchange = (html) => {
        this.info_ = html // 绑定当前逐渐地值
        this.$emit('change', this.info_) // 将内容同步到父组件中
      }
      this.editor.config.menus = [
        'source',  // 标题
        'head',  // 标题
        'bold',  // 粗体
        'fontSize',  // 字号
        'fontName',  // 字体
        'italic',  // 斜体
        'underline',  // 下划线
        'strikeThrough',  // 删除线
        'foreColor',  // 文字颜色
        'backColor',  // 背景颜色
        'link',  // 插入链接
        'list',  // 列表
        'justify',  // 对齐方式
        'quote',  // 引用
        'emoticon',  // 表情
        'image',  // 插入图片
        'video',
        'table',  // 表格
        'code',  // 插入代码
        'undo',  // 撤销
        'redo'  // 重复
      ]
      // 注册菜单
      this.editor.menus.extend('alertMenuKey', GetSource)
      this.editor.config.menus = this.editor.config.menus.concat('alertMenuKey')
      this.editor.create()
      // this.editor.txt.html(this.desc)
      this.editor.txt.html(this.desc)
    }
  },
  mounted() {
    // console.log('mounted editor', this.desc)
    this.initE();
  }
}
</script>

<style>
  .w-e-text-container {
    height: 600px !important;
    z-index: 5 !important;
  }
  .w-e-toolbar {
    z-index: 6 !important;
  }
</style>
